<?php


namespace App\Repositories;


use App\Models\OrderProduct;
use App\Models\Shipment as Model;
use App\Traits\CodeTrait;
use App\Traits\Logs;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use LTools\Repositories\RepositoryAbstract;

class Shipment extends RepositoryAbstract
{
    use Logs, CodeTrait;

    /**
     * Shipment constructor.
     * @param Model $model
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    /**
     * @param array $attributes
     * @param int|null $perPage
     * @param array $columns
     * @param string $pageName
     * @param int|null $page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function paginate(array $attributes, int $perPage = null, array $columns = ['*'], $pageName = 'page', int $page = null)
    {
        return $this->model->with(['express'])->where(
            $attributes
        )->paginate($perPage, $columns, $pageName, $page);
    }

    /**
     * @param array $attributes
     * @return bool|\Illuminate\Database\Eloquent\Model
     */
    public function create(array $attributes = [])
    {
        $attributes['code'] = $this->unique(5, 'P' . date("ymd"));
        return parent::create($attributes); // TODO: Change the autogenerated stub
    }

    /**
     * @param $id
     * @param array $values
     * @return array
     * @throws Exception
     * @author luffyzhao@vip.126.com
     */
    public function showCode($id, array $values)
    {
        /** @var Model $model */
        $model = $this->find($id);
        if ($model->getAttribute('status') === 0) {
            try {
                /** @var \App\Models\Order $order */
                $order = \App\Models\Order::query()
                    ->where('express_code', '=', $values['express_code'])
                    ->where('express_id', '=', $model->getAttribute('express_id'))
                    ->firstOrFail();
                $order->loadMissing("products.consumable");
                // 产品重量
                $weight = $order->getAttribute('weight');
                // 耗材重量
                /** @var OrderProduct $product */
                foreach ($order->products as $product) {
                    /** @var \App\Models\Consumable $consumable */
                    foreach ($product->consumable as $consumable) {
                        $weight += $consumable->getAttribute('weight') * $product->getAttribute('quantity');
                    }
                }
                // 包材
                $weight += $order->pack->package->getAttribute('weight');


                $system = System::getGroup('base');
                $min = bcsub($weight, $system->get('shipment_weight_diff', 0.1), 3);
                $max = bcadd($weight, $system->get('shipment_weight_diff', 0.1), 3);

                $response = ['status' => 0, 'weight' => $values['weight'], 'sys_weight' => $weight];

                if (bccomp($values['weight'], $min, 3) === 1 && bccomp($max, $values['weight'], 3) === 1) {
                    $response['status'] = 1;
                }

                return $response;

            } catch (ModelNotFoundException $exception) {
                throw new Exception("物流单号不存在！");
            }
        }
        throw new Exception("出货单不是草稿状态，不能加挂订单！");
    }

    /**
     * @param $id
     * @param array $values
     * @return Model|bool|\Illuminate\Database\Eloquent\Model
     * @throws \Throwable
     */
    public function update($id, array $values)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->lockForUpdate()->findOrFail($id);
        if ($model->getAttribute('status') === 0) {
            /** @var \App\Models\Order $order */
            try {
                $order = \App\Models\Order::query()
                    ->where('express_code', '=', $values['express_code'])
                    ->where('express_id', '=', $model->getAttribute('express_id'))
                    ->firstOrFail();
            } catch (ModelNotFoundException $exception) {
                throw new Exception("物流单号不存在！");
            }

            // 加锁
            $order = $order->where('id', '=', $order->getKey())->lockForUpdate()->first();

            if ($model->getAttribute('express_id') !== $order->getAttribute('express_id')) {
                throw new Exception("出货总单和订单的快递方式不一样！！");
            }
            // 订单状态
            if ($order->getAttribute('status') === 4) {
                // 订单拦截状态
                if ($order->getAttribute('intercept_status') === 0) {
                    $order->setAttribute('status', 5);
                    $order->saveOrFail();
                    // 日志
                    $this->recordLogs($order, "订单出货");

                    // 把订单添加到出货总单明细
                    $model->detail()->create([
                        'order_id' => $order->getKey(),
                        'weight' => $values['weight'],
                    ]);

                    // 出货批次状态更改
                    tap($order->shipment, function (\App\Models\OrderShipment $shipment) {
                        $shipment->setAttribute('status', 4);
                        $shipment->saveOrFail();
                        $this->recordLogs($shipment, "订单出货");
                    });

                    // 扣库存
                    foreach ($order->products as $item) {
                        $item->inventory->decrement('locked', $item->getAttribute('quantity'));
                        $this->recordLogs($item->product, sprintf("订单[%s]发货，数量[%d]", $order->getAttribute('code'), $item->getAttribute('quantity')));
                    }

                    // 出货单
                    $model->increment('count', 1, [
                        'weight' => DB::raw('weight + ' . $values['weight']),
                        'net_weight' => DB::raw('net_weight + ' . $order['net_weight']),
                        'price' => DB::raw('price + ' . $order['price']),
                    ]);


                    return $model;
                }

                throw new Exception("订单是拦截状态,不能出货！");
            }
            throw new Exception("订单不是待出货状态！");
        }
        throw new Exception("出货总单状态不对不能添加订单！");
    }
}
